#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctime>
#include <fstream>
#include <vector>
#include <unistd.h>
#include <cstring>
#include <fcntl.h>
#include <cstdio>
#include <boost/algorithm/string.hpp>
// 为提供的文件名添加后缀形成路径，可执行程序或者标准错误文件
const std::string _path = "./temp/";
const int MAXSIZE = 1024;
namespace expand
{

    class Expand
    {
    public:
        // 接收的文件全部放在temp目录下
        // e.g:对于一个文件名test，要扩展成./temp/test.cpp
        static std::string add_Path_Suffix(const std::string &file_name, const std::string suffix)
        {
            std::string pathName = _path;
            pathName += file_name;
            pathName += suffix;
            return pathName;
        }

        static std::string Src(const std::string &file_name)
        {
            // 源文件路径
            return add_Path_Suffix(file_name, ".cpp");
        }

        static std::string Exe(const std::string &file_name)
        {
            // 可执行程序路径
            return add_Path_Suffix(file_name, ".exe");
        }

        static std::string ComplieError(const std::string &file_name)
        {
            // complieStderror
            return add_Path_Suffix(file_name, ".complieStderr");
        }

        static std::string Stderror(const std::string &file_name)
        {
            // 运行错误信息stderror
            return add_Path_Suffix(file_name, ".stderr");
        }

        static std::string Stdout(const std::string &file_name)
        {
            // 输出结果stdout
            return add_Path_Suffix(file_name, ".stdout");
        }

        static std::string Stdin(const std::string &file_name)
        {
            // 用户自定义输入stdin
            return add_Path_Suffix(file_name, ".stdin");
        }

        static std::string uniqueName()
        {
            // 生成唯一文件名 年-月-日-时间
            // 用时间
            time_t timestamp = time(nullptr);
            struct tm *mytime = gmtime(&timestamp);
            mytime->tm_hour += 8; // 特殊情况处理
            std::string timeFormat = "[%Y-%m-%d:%H:%M:%S]";
            char timeBuffer[50];
            strftime(timeBuffer, sizeof(timeBuffer), timeFormat.c_str(), mytime);
            std::string name = timeBuffer;
            // std::cout << name << std::endl; //debug
            return name;
        }

        // 在temp目录下创建对应的文件，同时将数据写入到文件中
        static bool writeToFile(const std::string &path_name, const std::string &code)
        {
            std::ofstream out(path_name);
            if (!out.is_open())
            {
                return false;
            }
            // 文件已经打开, 写入数据
            out.write(code.c_str(), code.size());
            out.close();
            return true;
        }

        static bool readFromFile(const std::string &path_name, std::string *output, bool keep)
        {
            (*output).clear();

            std::ifstream in(path_name);
            if (!in.is_open())
            {
                return false;
            }
            std::string line;
            // getline自动将换行符去掉
            // getline返回值强制类型转化成bool
            while (std::getline(in, line))
            {
                *output += line;
                if (keep)
                    *output += '\n'; // 可能需要保留
            }
            in.close();
            return true;
        }
    };

    class FileExist
    {
    public:
        // 判断错误文件中是否存在信息

        static bool isFileExists(const std::string &path_name)
        {
            // 如果打开文件成功代表文件存在
            // 存在问题:如果多次编译，第一次生成的错误文件会影响后面的判断
            // int fd = open(path_name.c_str(), O_RDONLY);
            // if (fd == -1)
            // {
            //     return false;
            // }
            // stat接口检查特定路径下文件是否存在
            struct stat tmp;
            // 检测属性
            if (0 == stat(path_name.c_str(), &tmp))
            {
                return true;
            }
            return false;
        }
    };

    // 字符串工具类
    class StringUtil
    {
    public:
        static void split(const std::string &str, std::vector<std::string> *out, const std::string &sep)
        {
            // 根据指定的分隔符sep对str进行分割，并将结果插入out中
            //第三个参数表示分隔符压缩，即连续的分割符会被当成一个分隔符处理
            boost::split(*(out), str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
        }
    };
}